package com.cloud.zuul.core;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cloud.zuul.bean.ReleaseInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.Charset;
import java.util.*;

@Slf4j
@Component
public class ConfigLoader {

    @Value("${spring.application.name}")
    private String appName;

    @Value("${spring.cloud.config.uri}")
    private String configUri;

    @Value("${spring.cloud.config.label}")
    private String configLable;

    @Value("${spring.cloud.config.username}")
    private String configUsername;

    @Value("${spring.cloud.config.password}")
    private String configPassword;

    private List<ReleaseInfo> releaseInfoList;

    private Set<String> excludePaths;

    /**
     * 加载
     */
    public void load() {
        //组装请求地址
        StringBuilder requestUrl = new StringBuilder(configUri);
        requestUrl.append("/").append(appName).append("/default").append("/").append(configLable);

        //调用配置中心
        String authStr = configUsername + ":" + configPassword;
        HttpHeaders headers = new HttpHeaders();
        headers.set("authorization", "Basic " + new String(Base64.encodeBase64(authStr.getBytes(Charset.forName("US-ASCII")))));
        String result = new RestTemplate().exchange(requestUrl.toString(), HttpMethod.GET, new HttpEntity<>(null, headers), String.class).getBody();

        //读取配置属性
        JSONArray propertySources = JSON.parseObject(result).getJSONArray("propertySources");
        if (propertySources.size() == 0) {
            return;
        }
        JSONObject properties = propertySources.getJSONObject(0).getJSONObject("source");
        log.info("load >>> {}", properties.toJSONString());

        //加载发布信息
        loadReleases(properties);

        //加载排除校验的路径
        loadExcludePaths(properties);
    }

    /**
     * 加载发布信息
     *
     * @param properties
     */
    private void loadReleases(JSONObject properties) {
        final String versionKey = "releases[@].version";
        final String userIdKey = "releases[@].userId";
        final String userAreaKey = "releases[@].userArea";
        final String placeHolder = "@";
        try {
            List<ReleaseInfo> releaseInfoList = new ArrayList<>();
            for (int i = 0; i < Short.MAX_VALUE; i++) {
                String version = properties.getString(versionKey.replace(placeHolder, i + ""));
                if (StringUtils.isEmpty(version)) {
                    break;
                }
                String userId = properties.getString(userIdKey.replace(placeHolder, i + ""));
                String userArea = properties.getString(userAreaKey.replace(placeHolder, i + ""));
                userArea = userArea == null ? "" : userArea;
                userId = userId == null ? "" : userId;

                ReleaseInfo releaseInfo = new ReleaseInfo();
                releaseInfo.setVersion(version);
                releaseInfo.setUserId(userId);
                releaseInfo.setUserArea(userArea);
                releaseInfoList.add(releaseInfo);
            }
            Collections.sort(releaseInfoList);
            this.releaseInfoList = releaseInfoList;
        } catch (Exception e) {
            log.error("loadReleases error", e);
        }
    }

    /**
     * 加载排除校验的路径
     * @param properties
     */
    private void loadExcludePaths(JSONObject properties) {
        final String excludePathsKey = "excludePaths[@]";
        final String placeHolder = "@";
        try {
            Set<String> excludePaths = new HashSet<>();
            for (int i = 0; i < Short.MAX_VALUE; i++) {
                String path = properties.getString(excludePathsKey.replace(placeHolder, i + ""));
                if (StringUtils.isEmpty(path)) {
                    break;
                }
                excludePaths.add(path);
            }
            this.excludePaths = excludePaths;
        } catch (Exception e) {
            log.error("loadExcludePaths error", e);
        }
    }

    public Set<String> getExcludePaths() {
        return excludePaths;
    }

    public List<ReleaseInfo> getReleaseInfoList() {
        return releaseInfoList;
    }
}
